package com.rjj.wlqq.tool.date;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 
 *                             _ooOoo_
 *                            o8888888o
 *                            88" . "88
 *                            (| -_- |)
 *                            O\  =  /O
 *                         ____/`---'\____
 *                       .'  \\|     |//  `.
 *                      /  \\|||  :  |||//  \
 *                     /  _||||| -:- |||||-  \
 *                     |   | \\\  -  /// |   |
 *                     | \_|  ''\---/''  |   |
 *                     \  .-\__  `-`  ___/-. /
 *                   ___`. .'  /--.--\  `. . __
 *                ."" '<  `.___\_<|>_/___.'  >'"".
 *               | | :  `- \`.;`\ _ /`;.`/ - ` : | |
 *               \  \ `-.   \_ __\ /__ _/   .-` /  /
 *          ======`-.____`-.___\_____/___.-`____.-'======
 *                             `=---='
 *          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 *                     佛祖保佑        永无BUG
 *            佛曰:
 *                   写字楼里写字间，写字间里程序员；
 *                   程序人员写程序，又拿程序换酒钱。
 *                   酒醒只在网上坐，酒醉还来网下眠；
 *                   酒醉酒醒日复日，网上网下年复年。
 *                   但愿老死电脑间，不愿鞠躬老板前；
 *                   奔驰宝马贵者趣，公交自行程序员。
 *                   别人笑我忒疯癫，我笑自己命太贱；
 *                   不见满街漂亮妹，哪个归得程序员？
*/

/**
 * 获得这个月中的每周的开始结束时间，这个月的周数
 *
 */
public class DateUtil {

    private static Logger logger = LoggerFactory.getLogger(DateUtil.class);

    public static final String EMDHMSZY = "EEE MMM dd HH:mm:ss z yyyy";
    public static final String CHAINA_STANDARD_TIME = "EEE MMM dd HH:mm:ss z yyyy";
    public static final String YMD_HMS = "yyy-MM-dd HH:mm:ss";
    public static final String YMD = "yyy-MM-dd";

    //日期格式是线程不安全的，使用
    private static ThreadLocal<SimpleDateFormat> SDFTL = ThreadLocal.withInitial(() -> new SimpleDateFormat(EMDHMSZY,Locale.ENGLISH));

    private static SimpleDateFormat getSimpleDateFormat(){
        return SDFTL.get();
    }

    private static final ThreadLocal<SimpleDateFormat> sdf = ThreadLocal.withInitial(() -> new SimpleDateFormat(YMD_HMS));


    /**
     *  格式化时间
     * @param date
     * 			 要格式化的时间
     * @param formatStr
     * 			要求格式换成的格式
     * @return
     * 			字符串
     */
    public static String format(Date date, String formatStr) {

        sdf.get().applyPattern(formatStr);
        return sdf.get().format(date);
    }

    /**
     * 格式化时间
     * @param date
     * 			要格式化的时间
     * @return
     * 			yyyy-MM-dd HH:mm:ss ——> 2018-02-03 12:12:12
     */
    public static String format(Date date) {
        return sdf.get().format(date);
    }

    /**
     *  字符串转换成时间
     * @param dateTime
     *  			字符串   要求格式必须是：EEE MMM dd HH:mm:ss z yyyy
     * @return
     * 				Date
     */
    public static Date parse(String dateTime) {
        return parse(dateTime, CHAINA_STANDARD_TIME);
    }

    /**
     * @Title: 时间转化
     * @author 任建军
     * @date 2018/12/25 15:07
     * @Description: Thu May 28 18:23:17 CST 2015  格式的时间转换为正常时间
     *
     * 使用threadLocal 保证线程安全
     */
    public static Date parse(String dateStr,String pattern){

        try {
            SimpleDateFormat dateFormat = getSimpleDateFormat();
            dateFormat.applyPattern(pattern);
            Date date = dateFormat.parse(dateStr);
            return date;
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }

        /*String dt="Thu May 28 18:23:17 CST 2015";
        SimpleDateFormat sdf1= new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);

        SimpleDateFormat sdf2= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        try {
            System.out.println(sdf2.format(sdf1.parse(dt)));
        } catch (ParseException e) {
            e.printStackTrace();
        }*/
    }


    /**  
      * @Title: 获取今天是星期几
      * @author 任建军
      * @date 2018/12/26 15:36
      * @Description: 今天是星期几
      */
    public static String getWeekOfDate(Date date) {
        String[] weekDaysName = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
        //String[] weekDaysCode = { "0", "1", "2", "3", "4", "5", "6" };
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int intWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        return weekDaysName[intWeek];
    }
    /**
     * 根据日期获得星期
     * @param date
     * @return
     */
    public static String getWeekNumOfDate(Date date) {
        //String[] weekDaysName = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
        String[] weekDaysCode = { "0", "1", "2", "3", "4", "5", "6" };
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int intWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        return weekDaysCode[intWeek];
    }

    /**
     * Java将Unix时间戳转换成指定格式日期字符串
     * @param unix 时间戳 如："1473048265";
     * @param pattern 要格式化的格式 默认："yyyy-MM-dd HH:mm:ss";
     *
     * @return 返回结果 如："2016-09-05 16:06:42";
     */
    public static String unix2String(String unix,String pattern){
        if(pattern == null){
            pattern = "yyyy-MM-dd HH:mm:ss";
        }
        Long timestamp = Long.parseLong(unix) * 1000;
        String date = new SimpleDateFormat(pattern).format(new Date(timestamp));
        return date;
    }

    /**
     * 日期格式字符串转换成时间戳
     *
     * @param dateStr 字符串日期
     * @param pattern  如：yyyy-MM-dd HH:mm:ss
     *
     * @return 把指定格式的时间字符串转化为时间unix
     */
    public static String date2TimeStamp(String dateStr, String pattern) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            return String.valueOf(sdf.parse(dateStr).getTime() / 1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 取得当前时间戳（精确到秒）
     *
     * @return nowTimeStamp
     */
    public static String getNowTimeStamp() {
        long time = System.currentTimeMillis();
        return String.valueOf(time / 1000);
    }

    /**
     * 年份相加减
     * @param time
     *             时间字符串 yyyy-MM-dd HH:mm:ss
     * @param num
     *             加的数，-num就是减去
     * @return
     *             减去相应的数量的年的日期
     * @throws ParseException
     */
    public static Date yearAddNum(Date time, Integer num) {

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.add(Calendar.YEAR, num);
        return calendar.getTime();
    }

    /**
     * 月份加减
     * @param time
     *           时间
     * @param num
     *           加的数，-num就是减去
     * @return
     *          减去相应的数量的月份的日期
     * @throws ParseException Date
     */
    public static Date monthAddNum(Date time, Integer num){

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.add(Calendar.MONTH, num);
        return calendar.getTime();
    }

    /**
     * 天数加减
     * @param time
     *           时间
     * @param num
     *           加的数，-num就是减去
     * @return
     *          减去相应的数量的天的日期
     * @throws ParseException Date
     */
    public static Date dayAddNum(Date time, Integer num){

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.add(Calendar.DAY_OF_MONTH, num);
        return calendar.getTime();
    }

    /**
     * 获取本月第一天时间
     */
    public static Date getMonthStartDate(){
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_MONTH,1);
      /*  System.out.println(calendar.getTime());*/
        return calendar.getTime();
    }

    /**
     * 获取本月最后一天
     * @return
     */
    public static Date getMonthEndDate(){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH,1);
        calendar.add(Calendar.DAY_OF_MONTH,-1);
        /*System.out.println(calendar.getTime());*/
        return calendar.getTime();
    }

    /**
     * 获取本周的开始时间
     */
    public Date getBeginWeekDate(Date date){
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
        /*
        周日是1 ，周一是 2 ，周二是 3
        所以，当周的第一天 = 当前日期 - 距离周一过了几天（周一过了0天，周二过了1天，   周日过了6天）
        2 - 周一的（dayofweek：2 ）= 0
        2 - 周二的（dayofweek：3 ）= -1
        .
        .
        2 - 周日的（dayofweek：1） = 1（这个是不符合的需要我们修改）===》2 - 周日的（dayofweek：1 ==》8 ） = -6
        */
        if (dayofweek == 1){
            dayofweek += 7;
        }
        cal.add(Calendar.DATE, 2 - dayofweek);
        return cal.getTime();
    }

    /**
     * 本周的结束时间
     * 开始时间 + 6天
     */
    public static Date getEndWeekDate(Date date){
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayofweek == 1){
            dayofweek += 7;
        }
        cal.add(Calendar.DATE, 8 - dayofweek);//2 - dayofweek + 6
        return cal.getTime();
    }

    public static void main(String[] args) {
        //getThisMonthWeekDate();
        //Date parse = parse("2015-11-1 12:22:11", YMD_HMS);
        //System.out.println(format(parse,YMD_HMS));
        //String weekOfDate = getWeekOfDate(new Date());
        //logger.info(weekOfDate);

    }




    /**
     * 合并时间段去掉重复的
     *
     * 时间合并 12：00：00----13：00：00   &  12：30：00 --- 14：00：00  =====》 12：00：00----14：00：00
     * @param usertime
     */
    public static void unionTime(List<UserTime> usertime){
        //顺序timesixth在最后，不可以改其他的可以改
		/*List<UserTime> usertime = new ArrayList<UserTime>();
		SimpleDateFormat sdf=new SimpleDateFormat("HH:mm");
		UserTime ut = new UserTime(1, sdf.parse("12:00"), sdf.parse("13:00"));
		UserTime ut2 = new UserTime(1, sdf.parse("12:30"), sdf.parse("15:00"));
		UserTime ut3 = new UserTime(1, sdf.parse("16:00"), sdf.parse("19:00"));
		usertime.add(ut);
		usertime.add(ut2);
		usertime.add(ut3);*/

        timesixth(usertime);
    }



    private static void timesixth(List<UserTime> usertime) {
        for(int i=0;i<usertime.size()-1;i++){
            int j=i+1;
            if(usertime.get(i).getUserid()==usertime.get(j).getUserid()){
                if(usertime.get(i).getEnd().after(usertime.get(j).getStart())
                        && usertime.get(i).getStart().before(usertime.get(j).getStart())
                        &&usertime.get(i).getEnd().before(usertime.get(j).getEnd())
                       ){
                    // |-----------|
                    //          |---------|
                    usertime.get(j).setStart(usertime.get(i).getStart());
                    usertime.remove(i);
                    timesixth(usertime);
                }else if(usertime.get(i).getEnd().equals(usertime.get(j).getStart())) {
                    // |------|
                    //        |-----|
                    usertime.get(j).setStart(usertime.get(i).getStart());
                    usertime.remove(i);
                    timesixth(usertime);
                }else if(usertime.get(i).getStart().before(usertime.get(j).getStart())
                        &&usertime.get(i).getEnd().equals(usertime.get(j).getEnd())
                ){
                    //     |----------|    结尾相等
                    //        |-------|
                    usertime.remove(j);

                    timesixth(usertime);
                }else if(usertime.get(i).getStart().after(usertime.get(j).getStart())
                        &&usertime.get(i).getEnd().equals(usertime.get(j).getEnd())){
                    //          |-----|    结尾相等
                    //        |-------|
                    usertime.remove(i);
                }else if(usertime.get(i).getStart().equals(usertime.get(j).getStart())
                        &&usertime.get(i).getEnd().before(usertime.get(j).getEnd())){
                    // |------------|
                    // |--------------|
                    usertime.remove(i);
                    timesixth(usertime);
                }else if(usertime.get(i).getStart().equals(usertime.get(j).getStart())
                        &&usertime.get(i).getEnd().after(usertime.get(j).getEnd())){
                    // |------------|
                    // |----------|
                    usertime.remove(j);
                    timesixth(usertime);
                }else if(usertime.get(i).getStart().equals(usertime.get(j).getStart())&&usertime.get(i).getEnd().equals(usertime.get(j).getEnd())){
                    // |----------|
                    // |----------|
                    usertime.remove(i);
                    timesixth(usertime);
                }else if(usertime.get(i).getStart().before(usertime.get(j).getStart())
                        &&usertime.get(i).getEnd().after(usertime.get(j).getStart())
                        && usertime.get(i).getStart().before(usertime.get(j).getEnd())
                        &&usertime.get(i).getEnd().after(usertime.get(j).getEnd())){
                    //     |----------|
                    //      |-------|
                    usertime.remove(j);

                    timesixth(usertime);
                }else if(usertime.get(i).getStart().after(usertime.get(j).getStart())
                        && usertime.get(i).getEnd().before(usertime.get(j).getEnd())
                ){
                    //            |------|
                    //          |---------|
                    usertime.remove(i);
                    timesixth(usertime);
                }else{

                }
                 /*  if(usertime.get(i).getEnd().before(usertime.get(i).getStart())){
                    // |--------|
                    //            |-------|
                    //不可以动
                }*/

            }
        }
    }

    public static class UserTime implements Comparable<UserTime>{
        private int userid;//用户ID
        private String title;//这个是在full calendar插件使用的时候用到，可以忽略
        private Date start;//开始时间
        private Date end;//结束时间
        public UserTime(int userid, Date begintime, Date endtime,String title){
            this.userid=userid;
            this.start=begintime;
            this.end=endtime;
            this.title=title;
        }

        @Override
        public int compareTo(UserTime o) {
            //先用用户ID排序，最后用时间
            if(this.userid != o.userid) {
                return this.userid - o.userid;
            }else{
                return this.start.compareTo(o.end);
            }
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public int getUserid() {
            return userid;
        }

        public void setUserid(int userid) {
            this.userid = userid;
        }

        public Date getStart() {
            return start;
        }

        public void setStart(Date begintime) {
            this.start = begintime;
        }

        public Date getEnd() {
            return end;
        }

        public void setEnd(Date endtime) {
            this.end = endtime;
        }

    }



    /*******************************用到类******************************************/

    //是否打印日志
    private static boolean isLog = false;

    /**
     * 获取本月周次和日期时间段信息
     *
     * @return
     */
    public static List<WeekInfoModel> getThisMonthWeekDate() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<WeekInfoModel> list = new ArrayList<WeekInfoModel>();

        // 1 获取本月的第一天
        Date firstDayOfMonth = getFirstDayOfMonth();
        Calendar firstDayOfMonthCal = Calendar.getInstance();
        firstDayOfMonthCal.setFirstDayOfWeek(Calendar.MONDAY);
        firstDayOfMonthCal.setTime(firstDayOfMonth);

        // 2 获取本月第一周第一天
        Date firstWeekFirstDay = getFirstDayOfFirstWeekOfMonth();
        Calendar firstWeekFirstDayCal = Calendar.getInstance();
        firstWeekFirstDayCal.setFirstDayOfWeek(Calendar.MONDAY);
        firstWeekFirstDayCal.setTime(firstWeekFirstDay);

        // 3 获取本次周期起止时间
        Date sDate = null;// 本月第一周第一天
        Date eDate = null;// 本月最后一周最后一天
        Calendar sCal = Calendar.getInstance();
        Calendar eCal = Calendar.getInstance();
        sCal.setFirstDayOfWeek(Calendar.MONDAY);
        sCal.setFirstDayOfWeek(Calendar.MONDAY);

        // 获取本月第一天是周几
        int weekDay = firstDayOfMonthCal.get(Calendar.DAY_OF_WEEK) - 1;

        // 如果是周末，起始时间就是本月第一周第一天
        // 否则起始时间就是本月第一周第一天 倒退7天
        if (weekDay == 6 || weekDay == 0 || weekDay == 1) {// 周六或周天
            sDate = firstWeekFirstDay;
        } else {
            firstWeekFirstDayCal.getTime();
            firstWeekFirstDayCal.add(Calendar.DATE, -7);
            sDate = firstWeekFirstDayCal.getTime();
        }
        sCal.setTime(sDate);

        // 结束时间是起始时间+34天（5周）
        eCal.setTime(sDate);
        eDate = eCal.getTime();
        eCal.add(Calendar.DATE, 34);
        eDate = eCal.getTime();

        Date cDate = new Date();
        if (cDate.getTime() < eDate.getTime()) {
            eDate = cDate;
        }

        if (isLog) {
            System.out.println(" 本月统计起止时间是：" + format.format(sDate) + " 到 "
                    + format.format(eDate));
            System.out
                    .println("-------------------------------------------------------------------------------");
        }

        // 4 循环得到周次信息
        for (int i = 0; i < 5; i++) {// 循环5周次
            WeekInfoModel model = new WeekInfoModel();
            Calendar endTime = Calendar.getInstance();
            endTime.setFirstDayOfWeek(Calendar.MONDAY);
            endTime.setTime(sDate);
            endTime.set(Calendar.HOUR_OF_DAY, 23);
            endTime.set(Calendar.MINUTE, 59);
            endTime.set(Calendar.SECOND, 59);
            endTime.add(Calendar.DATE, 6);

            model.setIndexOfWeek(i + 1);
            model.setStartDateOfWeek(sDate);
            model.setEndDateOfWeek(endTime.getTime());

            Date currDate = new Date();
            // 如果当前时间在某个周次内
            if (sDate.getTime() < currDate.getTime()
                    && endTime.getTime().getTime() > currDate.getTime()) {
                model.setEndDateOfWeek(currDate);

                if (isLog) {
                    System.out.println(" 本月第" + (i + 1) + "周起止时间是："
                            + format.format(sDate) + " 到 "
                            + format.format(currDate));
                }
                list.add(model);
                break;
            }
            if (isLog) {
                System.out.println(" 本月第" + (i + 1) + "周起止时间是："
                        + format.format(sDate) + " 到 "
                        + format.format(endTime.getTime()));
            }
            list.add(model);

            sCal.add(Calendar.DATE, 7);
            sDate = sCal.getTime();
        }

        return list;
    }

    // 获取本月第一天
    public static Date getFirstDayOfMonth() {
        Calendar now = Calendar.getInstance();
//        Date date = new Date(2015 - 1900, 12 - 1, 1);
//        now.setTime(date);
        now.set(Calendar.DATE, now.getActualMinimum(Calendar.DATE));
        now.set(Calendar.HOUR_OF_DAY, 0);
        now.set(Calendar.MINUTE, 0);
        now.set(Calendar.SECOND, 0);
        return now.getTime();
    }

    // 获取本月第一周第一天
    public static Date getFirstDayOfFirstWeekOfMonth() {
        Calendar now = Calendar.getInstance();
        now.setFirstDayOfWeek(Calendar.MONDAY);
        now.setTime(getFirstDayOfMonth());

        int i = 1;
        while (now.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
            now.set(Calendar.DAY_OF_MONTH, i++);// 设置这个月的星期1 为几号
        }

        Date firstMonday = now.getTime();// 取得日期和时间
        String dtStr = new SimpleDateFormat("yyyy-MM-dd").format(firstMonday);// 格式化日期
        if (isLog) {
            System.out
                    .println("-------------------------------------------------------------------------------");
            System.out.println(" 本月第一周第一天是：" + dtStr);
            System.out
                    .println("-------------------------------------------------------------------------------");
        }
        return now.getTime();
    }

    /**
     * 获取本周周次和日期时间段信息
     *
     * @return
     */
    public static WeekInfoModel getThisWeekDate() {

        WeekInfoModel model = new WeekInfoModel();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        // 根据今天的时间获取本周属于本月的第几周
        Calendar now = Calendar.getInstance();
        now.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); // 获取本周一的日期

        int wom = now.get(Calendar.WEEK_OF_MONTH);
        model.setIndexOfWeek(wom);

        // 根据今天的时间获取本周的开始时间
        now.set(Calendar.HOUR_OF_DAY, 0);
        now.set(Calendar.MINUTE, 0);
        now.set(Calendar.SECOND, 0);
        now.set(Calendar.MILLISECOND, 0);
        System.out.println("********" + now.get(Calendar.YEAR) + "年"
                + ((now.get(Calendar.MONTH)) + 1) + "月第" + wom + "周星期一的日期是："
                + df.format(now.getTime()));
        model.setStartDateOfWeek(now.getTime());

        // 根据今天的时间获取本周的结束时间
        now.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        now.add(Calendar.WEEK_OF_YEAR, 1);
        now.set(Calendar.HOUR_OF_DAY, 23);
        now.set(Calendar.MINUTE, 59);
        now.set(Calendar.SECOND, 59);
        now.set(Calendar.MILLISECOND, 999);
        System.out.println("********" + now.get(Calendar.YEAR) + "年"
                + ((now.get(Calendar.MONTH)) + 1) + "月第" + wom + "周星期天的日期是："
                + df.format(now.getTime()));
        model.setEndDateOfWeek(now.getTime());

        return model;
    }

    static class WeekInfoModel{
        private Date endDateOfWeek;
        private Date startDateOfWeek;
        private int indexOfWeek;
        public Date getEndDateOfWeek() {
            return endDateOfWeek;
        }
        public void setEndDateOfWeek(Date endDateOfWeek) {
            this.endDateOfWeek = endDateOfWeek;
        }
        public Date getStartDateOfWeek() {
            return startDateOfWeek;
        }
        public void setStartDateOfWeek(Date startDateOfWeek) {
            this.startDateOfWeek = startDateOfWeek;
        }
        public int getIndexOfWeek() {
            return indexOfWeek;
        }
        public void setIndexOfWeek(int indexOfWeek) {
            this.indexOfWeek = indexOfWeek;
        }
        
        
    }
}